package com.dhj.yygh.api;

import com.alibaba.fastjson.JSONObject;
import com.dhj.yygh.common.exception.YyghException;
import com.dhj.yygh.common.helper.JwtHelper;
import com.dhj.yygh.common.result.MyResult;
import com.dhj.yygh.common.result.ResultCodeEnum;
import com.dhj.yygh.model.user.UserInfo;
import com.dhj.yygh.service.UserInfoService;
import com.dhj.yygh.utils.ConstantWxPropertiesUtiils;
import com.dhj.yygh.utils.HttpClientUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.UnsupportedEncodingException;

import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

@Api(tags = "微信操作相关的接口")
@Controller
@RequestMapping("/api/ucenter/wx")
@Slf4j
public class WxApiController {

    @Autowired
    UserInfoService userInfoService;

    /*
     生成微信扫描的二维码
     */
    @ApiOperation("返回生成二维码需要的参数")
    @GetMapping("/getWxQrcodeParam")
    @ResponseBody
    public MyResult<Map<String, Object>> getQrConnect() {
        Map<String, Object> paramMap = new HashMap<>();

        // 需要对 redirect_uri 进行 utf-8 编码
        try {
            paramMap.put("appid", ConstantWxPropertiesUtiils.WX_OPEN_APP_ID);
            paramMap.put("scope", "snsapi_login");
            String redirect_uri = ConstantWxPropertiesUtiils.WX_OPEN_REDIRECT_URL;
            log.info("编码前:" + redirect_uri);
            redirect_uri = URLEncoder.encode(redirect_uri, "utf-8");
            log.info("编码后:" + redirect_uri);
            paramMap.put("redirect_uri", redirect_uri);
            paramMap.put("state", System.currentTimeMillis() + "");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return MyResult.ok(paramMap);
    }

    /*
     回调方法，得到扫码人的信息

     当扫描微信官方提供的二维码后，用户在微信客户端进行确认，确认后会调用微信后台配置的回调地址，该地址为
     微信提供给认证后的微信开发者的
     这里为了能够在本地 ip 进行开发，使用内网穿透将回调的地址映射到本地的 localhost:8150 端口
     因此，该微服务需要运行在 8150 端口

     以下目标方法在 localhost:8150 端口监听微信的回调地址
     获取到回调地址中的 code 和 state 参数值
     */
    @ApiOperation("微信回调接口")
    @GetMapping("/callback")
    public String callBack(String code, String state) {
        Map<String, Object> map = null; // 用于封装用户的信息

        /*
         获取 code 微信提供的临时票据
         */
        // 已经自动注入到参数 code
        log.info("code: " + code);

        /*
         使用 code 值，请求微信提供的地址，得到返回的两个值
         access_token 访问的凭证
         openid 每个人微信的一个唯一标识
         */
        //使用 code 和 appid 以及 appscrect 换取 access_token
        StringBuffer baseAccessTokenUrl = new StringBuffer()
                .append("https://api.weixin.qq.com/sns/oauth2/access_token") // 请求微信的固定地址
                .append("?appid=%s") // 拼接参数
                .append("&secret=%s")
                .append("&code=%s")
                .append("&grant_type=authorization_code");

        // 设置上面 url 占位符处的参数值
        String accessTokenUrl = String.format(baseAccessTokenUrl.toString(),
                ConstantWxPropertiesUtiils.WX_OPEN_APP_ID,
                ConstantWxPropertiesUtiils.WX_OPEN_APP_SECRET,
                code);

        log.info("第一次请求微信的地址: " + accessTokenUrl);

        //通过 httpclient 使用 get 方式 请求微信提供的固定地址
        String result;
        try {
            result = HttpClientUtils.get(accessTokenUrl);
        } catch (Exception e) {
            throw new YyghException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
        }

        log.info("第一次请求微信返回的结果: " + result);

        // 转化 json 字符串为对象
        JSONObject resultObj = JSONObject.parseObject(result);

        /*
        使用 access_token 和 openid 再去请求微信提供的地址,返回扫码人的信息，包括(昵称，头像等信息)
         */

        String openid = resultObj.getString("openid");
        String access_token = resultObj.getString("access_token");

        log.info("openid: " + openid + "\n" + "access_token: " + access_token);

        // 先根据 openid 查询是否有用户的微信登录信息，有则直接重定向
        UserInfo existUserInfo = userInfoService.getUserInfoByOpenId(openid);

        if (existUserInfo != null) {
            map = new HashMap<>();
            String name = existUserInfo.getName();
            if (StringUtils.isEmpty(name)) {
                name = existUserInfo.getNickName();
            }
            if (StringUtils.isEmpty(name)) {
                name = existUserInfo.getPhone();
            }
            map.put("name", name);

            // 后续可以根据 openid 判断是否绑定了手机号
            if (StringUtils.isEmpty(existUserInfo.getPhone())) {
                map.put("openid", existUserInfo.getOpenid());
            } else {
                map.put("openid", "");
            }
            String token = JwtHelper.createToken(existUserInfo.getId(), name);
            map.put("token", token);
            try {
                return "redirect:"
                        + ConstantWxPropertiesUtiils.YYGH_BASE_URL
                        + "/weixin/callback?token=" + map.get("token")
                        + "&openid="
                        + map.get("openid")
                        + "&name=" + URLEncoder.encode((String) map.get("name"), "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return null;
            }
        }


        String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                "?access_token=%s" +
                "&openid=%s";

        // 再次请求微信
        String userInfoUrl = String.format(baseUserInfoUrl, access_token, openid);
        String resultUserInfo = null;
        try {
            resultUserInfo = HttpClientUtils.get(userInfoUrl);
        } catch (Exception e) {
            throw new YyghException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }
        log.info("使用 access_token 获取用户信息的结果: " + resultUserInfo);

        JSONObject resultUserInfoJson = JSONObject.parseObject(resultUserInfo);
        if (resultUserInfoJson.getString("errcode") != null) {
            log.error("获取用户信息失败：" + resultUserInfoJson.getString("errcode") + resultUserInfoJson.getString("errmsg"));
            throw new YyghException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }

        //解析用户信息
        String nickname = resultUserInfoJson.getString("nickname"); // 昵称
        String headimgurl = resultUserInfoJson.getString("headimgurl"); // 头像

        UserInfo userInfo = new UserInfo();
        userInfo.setOpenid(openid);
        userInfo.setNickName(nickname);
        userInfo.setStatus(1);

        // 保存用户微信登录的信息
        userInfoService.save(userInfo);


        map = new HashMap<>();
        String name = userInfo.getName();
        if (StringUtils.isEmpty(name)) {
            name = userInfo.getNickName();
        }
        if (StringUtils.isEmpty(name)) {
            name = userInfo.getPhone();
        }
        map.put("name", name);

        // 后续可以根据 openid 判断是否绑定了手机号
        if (StringUtils.isEmpty(userInfo.getPhone())) {
            map.put("openid", userInfo.getOpenid());
        } else {
            map.put("openid", "");
        }
        String token = JwtHelper.createToken(userInfo.getId(), name);
        map.put("token", token);

        try {
            return "redirect:"
                    + ConstantWxPropertiesUtiils.YYGH_BASE_URL
                    + "/weixin/callback?token=" + map.get("token")
                    + "&openid="
                    + map.get("openid")
                    + "&name=" + URLEncoder.encode((String) map.get("name"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }
}
